#!/usr/bin/env python
# -*- coding:utf-8 -*-

# vi:ts=4 sw=4 et

from simulador import Simulador
from itertools import chain
import pylab

class Cenario():
    def __init__(self, b, mu, u, gamma, n0, p, lambida, n_rodadas, tam_rodada, blocos_iniciais, eventos_transientes, dt, epsilon):
        """Inicialização dos parâmetros do cenário
        """
        self.epsilon = epsilon

        self.simulador = Simulador(b, mu, u, gamma, n0, p, lambida, blocos_iniciais, tam_rodada, n_rodadas, eventos_transientes, dt)

    def get_tempo_medio_download(self):
        tempos = []
        tempos += [ s.virou_seed - s.chegada for s in chain(self.simulador.seeds, self.simulador.seeds_sairam) if s.rodada_entrou == s.rodada_saiu and s.rodada_entrou != 0]
        media = pylab.average(tempos)
        desvpad = pylab.var(tempos) ** 0.5
        f = 2.96
        delta = f * desvpad / len(tempos)

        return media, media-delta, media+delta


    def get_tempo_fase_transiente_sistema_fechado(self):
        raise NotImplementedError()

    def gera_grafico(self):
        n = [l[1] for l in self.simulador.anotacao_tempo]
        print n
        print pylab.hist(n, bins=(max(n)), normed=True)
        pylab.show()


    def get_tempo_fase_transiente_sistema_aberto(self):
        """Peers
        """
        xs = []
        ys = []
        tempo_transiente = 0
        convergiu = False

        for t, n in self.simulador.anotacao_tempo: 
            xs.append(t)

            if t == 0:
                y = 0
            else:
                y = (ys[-1] + n * self.simulador.dt)/t

                if not convergiu and (ys[-1] - y) < self.epsilon:
                    tempo_transiente = t
                    convergiu = True

            ys.append(y)
         
        return tempo_transiente


    def get_tempo_fase_transiente(self):
        if self.simulador.lambida == 0 and self.simulador.p == 1:
            return self.get_tempo_fase_transiente_sistema_fechado()
        return self.get_tempo_fase_transiente_sistema_aberto()

 

    def run(self):
        """
        1. Rodar para obter o número de eventos a descartar (fase transiente);
        2. Rodar com o valor obtido;
        3. Coletar as estatísticas.

        def: sistema fechado: população constante -> Lambda 0 e p = 1
        """

        self.simulador.start()
        self.simulador.run()

        self.simulador.eventos_transientes = self.get_tempo_fase_transiente()
        self.simulador.n_rodadas = 10
        self.simulador.run() 

        media, baixo, alto = self.get_tempo_medio_download()
        print media, baixo, alto

        self.gera_grafico()

        self.simulador.debug_print("\nFim\n")
        
        self.simulador.debug_print("publisher {0}".format(self.simulador.publisher))
        self.simulador.debug_print("seeds {0}".format(self.simulador.seeds))
        self.simulador.debug_print("seeds_sairam {0}".format(self.simulador.seeds_sairam))
        self.simulador.debug_print("peers {0}".format(self.simulador.peers))
        self.simulador.debug_print("peers no tempo {0}".format(self.simulador.anotacao_tempo))



if __name__ == '__main__':

    from argparse import ArgumentParser
    parser = ArgumentParser()
    parser.add_argument('-lambda', dest='lambida', type=float,
        help='chegadas externas (peers/s)')
    parser.add_argument('-B', dest='blocos', type=int, 
        help='numero de blocos do arquivo')
    parser.add_argument('-mu', dest='mu', type=float,
        help='taxa de upload seed e peer (blocos/s)')
    parser.add_argument('-u', dest='u', type=float,
        help='taxa de upload publisher (blocos/s)')
    parser.add_argument('-gamma', dest='gamma', type=float,
        help='taxa de saida (1/s)')
    parser.add_argument('-p', dest='p', type=float,
        help='probabilidade de aceitacao de recomendacao')
    parser.add_argument('-n0', dest='n0', type=int,
        help='populacao inicial')
    parser.add_argument('-n_rodadas', dest='n_rodadas', type=int,
        help='numero de rodadas')
    parser.add_argument('-tam_rodada', dest='tam_rodada', type=int,
        help='tamanho de cada rodada em número de eventos processados')
    parser.add_argument('-blocos_iniciais', dest='blocos_iniciais', type=int,
        help='blocos que os peers já tem no início do sistema')
    parser.add_argument('-eventos_descartados', dest='eventos_descartados', type=int,
        help='eventos a serem descartados (fase transiente)')
    parser.add_argument('-epsilon', dest='epsilon', type=float,
        help='variação da fase transiente)')

    parser.add_argument('-dt', dest='dt', type=float,
        help='variação da fase transiente)')




    args = parser.parse_args()
    cenario = Cenario(lambida=args.lambida, 
        b=args.blocos, 
        mu=args.mu, 
        u=args.u, 
        gamma=args.gamma, 
        p=args.p, 
        n0=args.n0, 
        n_rodadas=args.n_rodadas,      
        tam_rodada=args.tam_rodada,      
        blocos_iniciais=args.blocos_iniciais,      
        eventos_transientes=args.eventos_descartados,
        dt=args.dt,
        epsilon=args.epsilon)      
    cenario.run()

